iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0

Table of Contents

  • 計時器
  • 顯示當下時間
  • 顯示結束時間
  • 按最上方一排的按鈕開始時間
  • 自行輸入指定時間
  • References

Yes
今天要來學製作一個倒數計時器。

計時器

首先我們要創建一個計時器的函式,先找出當下開始的時間與結束的時間,用setInterval()方法執行倒數秒數,每1000毫秒(1秒)會執行一次顯示一次當下秒數,藉由結束時間扣除當下的時間,如果secondsLeft變成0,那麽我們需要清除計時器,並且結束。

let countdown;
function timer(seconds) {
  //Date.now會以毫秒計算現在的時間
  const now = Date.now();
  //傳入的秒數也需要換算成毫秒,並加上想執行的時長
  const then = now + seconds * 1000;
  //每指定的時間到就執行function
  countdown = setInterval(() => {
    //剩餘的秒數需要預計的時間扣掉每一秒顯示的時間
    //但是會發現這樣扣除時間時會有小數點的誤差,所以用Math.round四捨五入進位回原本的數值。
    const secondsLeft = Math.round((then - Date.now()) / 1000);
    if (secondsLeft < 0) {
      clearInterval(countdown);
      return;
    }
    console.log(secondsLeft);
  }, 1000);
}

顯示當下時間

但假如我們執行timer(10),第一次回傳的秒數會是9,但希望可以從傳入的參數開始倒數計時,所以我們需要一個函式,不僅在每次使用setInterval()倒數時,都能從指定的時間開始顯示倒數,也能夠渲染在畫面上。

function timer(seconds) {
  const now = Date.now();
  const then = now + seconds * 1000;
  //顯示一開始的時間
  displayTimeLeft(seconds);
  countdown = setInterval(() => {
    const secondsLeft = Math.round((then - Date.now()) / 1000);
    if (secondsLeft < 0) {
      clearInterval(countdown);
      return;
    }
     //顯示開始計時的時間
    displayTimeLeft(secondsLeft);
  }, 1000);
}

function displayTimeLeft(seconds) {
  //Math.floor會往負數捨去後面小數點到最接近的整數
  const minute = Math.floor(seconds / 60);
  //取秒數除以分鐘的餘數
  const remainderSeconds = seconds % 60;
  //${remainderSeconds < 10 ? "0" : ""}這段是決定秒數小於10時要出現0為開頭
  const display = `${minute}:${remainderSeconds < 10 ? "0" : ""}${remainderSeconds}`;
  //讓網頁的名稱可以顯示當下倒數計時的秒數
  document.title = display;
  //插入時間
  timerDisplay.textContent = display;
}

顯示結束時間

在網頁的中間有斗大的計時器,下面會接一行顯示結束的時間,所以我們需要做顯示計時器的做法,能把結束時間一起渲染出來。

function timer(seconds) {
  const now = Date.now();
  const then = now + seconds * 1000;
  displayTimeLeft(seconds);
    //將預計結束的時間傳進去
  displayEndTime(then);
  countdown = setInterval(() => {
    const secondsLeft = Math.round((then - Date.now()) / 1000);
    if (secondsLeft < 0) {
      clearInterval(countdown);
      return;
    }
    displayTimeLeft(secondsLeft);
  }, 1000);
}

function displayEndTime(timestamp){
  //轉換時間格式
  //產生這個物件之後,可以得到像是月份的數值
  const end = new Date(timestamp);
  //取得指定時間單位的數值
  const hour = end.getHours();
  const minute = end.getMinutes();
  //因為習慣24小時制,所以就不讓hour超過12之後減去12
  endTime.textContent = `Be Back At${hour}:${minute< 10 ? "0" : ""}${minute}`
}

按最上方一排的按鈕開始時間

最上方分別已經有設定好的時間跟樣式,只要在相對的按鈕中執行相對時間就可以了,但是如果我們分別按太多時間,會導致事件變得不太正常,所以要在計時器的一開始就先清除。

function timer(seconds) {
  //每一次執行都要清除上一回執行的計時器
  clearInterval(countdown);
    
  const now = Date.now();
  const then = now + seconds * 1000;
  displayTimeLeft(seconds);
    //將預計結束的時間傳進去
  displayEndTime(then);
  countdown = setInterval(() => {
    const secondsLeft = Math.round((then - Date.now()) / 1000);
    if (secondsLeft < 0) {
      clearInterval(countdown);
      return;
    }
    displayTimeLeft(secondsLeft);
  }, 1000);
}

function startTimer(event){
  const seconds = parseInt(event.target.dataset.time)
  timer(seconds);
}

buttons.forEach(button => button.addEventListener('click', startTimer));

自行輸入指定時間

右上角有一欄可以自行指定倒數時間的輸入框,首先要在submit停止預設事件,防止按出之後直接更新,再來就執行時間,不過我在中間有擋掉自行輸入0或者不是數字的內容。

比較特別的是form只要有name屬性,就能透過這個屬性得到已經存在的節點。

function getTime(event){
  event.preventDefault();
  const minutes = Number(this.minutes.value)
  if (Number.isNaN(minutes)||minutes===0){
    alert('please input number')
    return;
  }
  timer(minutes*60);
  this.reset();
}

document.customForm.addEventListener('submit',getTime);

References

MDN
Math.round()
clearInterval() global function
W3School
JavaScript Timing Events
JavaScript Math.floor()


上一篇
〈Day27〉Geolocation API
下一篇
〈Day29〉speechSynthesisAPI
系列文
廚藝不精也可以,給自己做一份Javascript小火鍋30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言